<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.6.6" />
<title>Release notes for Gerrit 2.0.21</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */

/* Default font. */
body {
  font-family: Georgia,serif;
}

/* Title font. */
h1, h2, h3, h4, h5, h6,
div.title, caption.title,
thead, p.table.header,
#toctitle,
#author, #revnumber, #revdate, #revremark,
#footer {
  font-family: Arial,Helvetica,sans-serif;
}

body {
  margin: 1em 5% 1em 5%;
}

a {
  color: blue;
  text-decoration: underline;
}
a:visited {
  color: fuchsia;
}

em {
  font-style: italic;
  color: navy;
}

strong {
  font-weight: bold;
  color: #083194;
}

h1, h2, h3, h4, h5, h6 {
  color: #527bbd;
  margin-top: 1.2em;
  margin-bottom: 0.5em;
  line-height: 1.3;
}

h1, h2, h3 {
  border-bottom: 2px solid silver;
}
h2 {
  padding-top: 0.5em;
}
h3 {
  float: left;
}
h3 + * {
  clear: left;
}
h5 {
  font-size: 1.0em;
}

div.sectionbody {
  margin-left: 0;
}

hr {
  border: 1px solid silver;
}

p {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

ul, ol, li > p {
  margin-top: 0;
}
ul > li     { color: #aaa; }
ul > li > * { color: black; }

pre {
  padding: 0;
  margin: 0;
}

#author {
  color: #527bbd;
  font-weight: bold;
  font-size: 1.1em;
}
#email {
}
#revnumber, #revdate, #revremark {
}

#footer {
  font-size: small;
  border-top: 2px solid silver;
  padding-top: 0.5em;
  margin-top: 4.0em;
}
#footer-text {
  float: left;
  padding-bottom: 0.5em;
}
#footer-badges {
  float: right;
  padding-bottom: 0.5em;
}

#preamble {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
}
div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.admonitionblock {
  margin-top: 2.0em;
  margin-bottom: 2.0em;
  margin-right: 10%;
  color: #606060;
}

div.content { /* Block element content. */
  padding: 0;
}

/* Block element titles. */
div.title, caption.title {
  color: #527bbd;
  font-weight: bold;
  text-align: left;
  margin-top: 1.0em;
  margin-bottom: 0.5em;
}
div.title + * {
  margin-top: 0;
}

td div.title:first-child {
  margin-top: 0.0em;
}
div.content div.title:first-child {
  margin-top: 0.0em;
}
div.content + div.title {
  margin-top: 0.0em;
}

div.sidebarblock > div.content {
  background: #ffffee;
  border: 1px solid #dddddd;
  border-left: 4px solid #f0f0f0;
  padding: 0.5em;
}

div.listingblock > div.content {
  border: 1px solid #dddddd;
  border-left: 5px solid #f0f0f0;
  background: #f8f8f8;
  padding: 0.5em;
}

div.quoteblock, div.verseblock {
  padding-left: 1.0em;
  margin-left: 1.0em;
  margin-right: 10%;
  border-left: 5px solid #f0f0f0;
  color: #888;
}

div.quoteblock > div.attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock > pre.content {
  font-family: inherit;
  font-size: inherit;
}
div.verseblock > div.attribution {
  padding-top: 0.75em;
  text-align: left;
}
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
div.verseblock + div.attribution {
  text-align: left;
}

div.admonitionblock .icon {
  vertical-align: top;
  font-size: 1.1em;
  font-weight: bold;
  text-decoration: underline;
  color: #527bbd;
  padding-right: 0.5em;
}
div.admonitionblock td.content {
  padding-left: 0.5em;
  border-left: 3px solid #dddddd;
}

div.exampleblock > div.content {
  border-left: 3px solid #dddddd;
  padding-left: 0.5em;
}

div.imageblock div.content { padding-left: 0; }
span.image img { border-style: none; }
a.image:visited { color: white; }

dl {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
dt {
  margin-top: 0.5em;
  margin-bottom: 0;
  font-style: normal;
  color: navy;
}
dd > *:first-child {
  margin-top: 0.1em;
}

ul, ol {
    list-style-position: outside;
}
ol.arabic {
  list-style-type: decimal;
}
ol.loweralpha {
  list-style-type: lower-alpha;
}
ol.upperalpha {
  list-style-type: upper-alpha;
}
ol.lowerroman {
  list-style-type: lower-roman;
}
ol.upperroman {
  list-style-type: upper-roman;
}

div.compact ul, div.compact ol,
div.compact p, div.compact p,
div.compact div, div.compact div {
  margin-top: 0.1em;
  margin-bottom: 0.1em;
}

tfoot {
  font-weight: bold;
}
td > div.verse {
  white-space: pre;
}

div.hdlist {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
div.hdlist tr {
  padding-bottom: 15px;
}
dt.hdlist1.strong, td.hdlist1.strong {
  font-weight: bold;
}
td.hdlist1 {
  vertical-align: top;
  font-style: normal;
  padding-right: 0.8em;
  color: navy;
}
td.hdlist2 {
  vertical-align: top;
}
div.hdlist.compact tr {
  margin: 0;
  padding-bottom: 0;
}

.comment {
  background: yellow;
}

.footnote, .footnoteref {
  font-size: 0.8em;
}

span.footnote, span.footnoteref {
  vertical-align: super;
}

#footnotes {
  margin: 20px 0 20px 0;
  padding: 7px 0 0 0;
}

#footnotes div.footnote {
  margin: 0 0 5px 0;
}

#footnotes hr {
  border: none;
  border-top: 1px solid silver;
  height: 1px;
  text-align: left;
  margin-left: 0;
  width: 20%;
  min-width: 100px;
}

div.colist td {
  padding-right: 0.5em;
  padding-bottom: 0.3em;
  vertical-align: top;
}
div.colist td img {
  margin-top: 0.3em;
}

@media print {
  #footer-badges { display: none; }
}

#toc {
  margin-bottom: 2.5em;
}

#toctitle {
  color: #527bbd;
  font-size: 1.1em;
  font-weight: bold;
  margin-top: 1.0em;
  margin-bottom: 0.1em;
}

div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
  margin-top: 0;
  margin-bottom: 0;
}
div.toclevel2 {
  margin-left: 2em;
  font-size: 0.9em;
}
div.toclevel3 {
  margin-left: 4em;
  font-size: 0.9em;
}
div.toclevel4 {
  margin-left: 6em;
  font-size: 0.9em;
}

span.aqua { color: aqua; }
span.black { color: black; }
span.blue { color: blue; }
span.fuchsia { color: fuchsia; }
span.gray { color: gray; }
span.green { color: green; }
span.lime { color: lime; }
span.maroon { color: maroon; }
span.navy { color: navy; }
span.olive { color: olive; }
span.purple { color: purple; }
span.red { color: red; }
span.silver { color: silver; }
span.teal { color: teal; }
span.white { color: white; }
span.yellow { color: yellow; }

span.aqua-background { background: aqua; }
span.black-background { background: black; }
span.blue-background { background: blue; }
span.fuchsia-background { background: fuchsia; }
span.gray-background { background: gray; }
span.green-background { background: green; }
span.lime-background { background: lime; }
span.maroon-background { background: maroon; }
span.navy-background { background: navy; }
span.olive-background { background: olive; }
span.purple-background { background: purple; }
span.red-background { background: red; }
span.silver-background { background: silver; }
span.teal-background { background: teal; }
span.white-background { background: white; }
span.yellow-background { background: yellow; }

span.big { font-size: 2em; }
span.small { font-size: 0.6em; }

span.underline { text-decoration: underline; }
span.overline { text-decoration: overline; }
span.line-through { text-decoration: line-through; }


/*
 * xhtml11 specific
 *
 * */

tt {
  font-family: monospace;
  font-size: inherit;
  color: navy;
}

div.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.tableblock > table {
  border: 3px solid #527bbd;
}
thead, p.table.header {
  font-weight: bold;
  color: #527bbd;
}
p.table {
  margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
  border-style: none;
}
div.tableblock > table[frame="hsides"] {
  border-left-style: none;
  border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
  border-top-style: none;
  border-bottom-style: none;
}


/*
 * html5 specific
 *
 * */

.monospaced {
  font-family: monospace;
  font-size: inherit;
  color: navy;
}

table.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
thead, p.tableblock.header {
  font-weight: bold;
  color: #527bbd;
}
p.tableblock {
  margin-top: 0;
}
table.tableblock {
  border-width: 3px;
  border-spacing: 0px;
  border-style: solid;
  border-color: #527bbd;
  border-collapse: collapse;
}
th.tableblock, td.tableblock {
  border-width: 1px;
  padding: 4px;
  border-style: solid;
  border-color: #527bbd;
}

table.tableblock.frame-topbot {
  border-left-style: hidden;
  border-right-style: hidden;
}
table.tableblock.frame-sides {
  border-top-style: hidden;
  border-bottom-style: hidden;
}
table.tableblock.frame-none {
  border-style: hidden;
}

th.tableblock.halign-left, td.tableblock.halign-left {
  text-align: left;
}
th.tableblock.halign-center, td.tableblock.halign-center {
  text-align: center;
}
th.tableblock.halign-right, td.tableblock.halign-right {
  text-align: right;
}

th.tableblock.valign-top, td.tableblock.valign-top {
  vertical-align: top;
}
th.tableblock.valign-middle, td.tableblock.valign-middle {
  vertical-align: middle;
}
th.tableblock.valign-bottom, td.tableblock.valign-bottom {
  vertical-align: bottom;
}


/*
 * manpage specific
 *
 * */

body.manpage h1 {
  padding-top: 0.5em;
  padding-bottom: 0.5em;
  border-top: 2px solid silver;
  border-bottom: 2px solid silver;
}
body.manpage h2 {
  border-style: none;
}
body.manpage div.sectionbody {
  margin-left: 3em;
}

@media print {
  body.manpage div#toc { display: none; }
}
</style>
<script type="text/javascript">
/*<![CDATA[*/
var asciidoc = {  // Namespace.

/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////

/* Author: Mihai Bazon, September 2002
 * http://students.infoiasi.ro/~mishoo
 *
 * Table Of Content generator
 * Version: 0.4
 *
 * Feel free to use this script under the terms of the GNU General Public
 * License, as long as you do not remove or alter this notice.
 */

 /* modified by Troy D. Hanson, September 2006. License: GPL */
 /* modified by Stuart Rackham, 2006, 2009. License: GPL */

// toclevels = 1..4.
toc: function (toclevels) {

  function getText(el) {
    var text = "";
    for (var i = el.firstChild; i != null; i = i.nextSibling) {
      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
        text += i.data;
      else if (i.firstChild != null)
        text += getText(i);
    }
    return text;
  }

  function TocEntry(el, text, toclevel) {
    this.element = el;
    this.text = text;
    this.toclevel = toclevel;
  }

  function tocEntries(el, toclevels) {
    var result = new Array;
    var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
    // Function that scans the DOM tree for header elements (the DOM2
    // nodeIterator API would be a better technique but not supported by all
    // browsers).
    var iterate = function (el) {
      for (var i = el.firstChild; i != null; i = i.nextSibling) {
        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
          var mo = re.exec(i.tagName);
          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
          }
          iterate(i);
        }
      }
    }
    iterate(el);
    return result;
  }

  var toc = document.getElementById("toc");
  if (!toc) {
    return;
  }

  // Delete existing TOC entries in case we're reloading the TOC.
  var tocEntriesToRemove = [];
  var i;
  for (i = 0; i < toc.childNodes.length; i++) {
    var entry = toc.childNodes[i];
    if (entry.nodeName == 'div'
     && entry.getAttribute("class")
     && entry.getAttribute("class").match(/^toclevel/))
      tocEntriesToRemove.push(entry);
  }
  for (i = 0; i < tocEntriesToRemove.length; i++) {
    toc.removeChild(tocEntriesToRemove[i]);
  }

  // Rebuild TOC entries.
  var entries = tocEntries(document.getElementById("content"), toclevels);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if (entry.element.id == "")
      entry.element.id = "_toc_" + i;
    var a = document.createElement("a");
    a.href = "#" + entry.element.id;
    a.appendChild(document.createTextNode(entry.text));
    var div = document.createElement("div");
    div.appendChild(a);
    div.className = "toclevel" + entry.toclevel;
    toc.appendChild(div);
  }
  if (entries.length == 0)
    toc.parentNode.removeChild(toc);
},


/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////

/* Based on footnote generation code from:
 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
 */

footnotes: function () {
  // Delete existing footnote entries in case we're reloading the footnodes.
  var i;
  var noteholder = document.getElementById("footnotes");
  if (!noteholder) {
    return;
  }
  var entriesToRemove = [];
  for (i = 0; i < noteholder.childNodes.length; i++) {
    var entry = noteholder.childNodes[i];
    if (entry.nodeName == 'div' && entry.getAttribute("class") == "footnote")
      entriesToRemove.push(entry);
  }
  for (i = 0; i < entriesToRemove.length; i++) {
    noteholder.removeChild(entriesToRemove[i]);
  }

  // Rebuild footnote entries.
  var cont = document.getElementById("content");
  var spans = cont.getElementsByTagName("span");
  var refs = {};
  var n = 0;
  for (i=0; i<spans.length; i++) {
    if (spans[i].className == "footnote") {
      n++;
      var note = spans[i].getAttribute("data-note");
      if (!note) {
        // Use [\s\S] in place of . so multi-line matches work.
        // Because JavaScript has no s (dotall) regex flag.
        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
        spans[i].innerHTML =
          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
        spans[i].setAttribute("data-note", note);
      }
      noteholder.innerHTML +=
        "<div class='footnote' id='_footnote_" + n + "'>" +
        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
        n + "</a>. " + note + "</div>";
      var id =spans[i].getAttribute("id");
      if (id != null) refs["#"+id] = n;
    }
  }
  if (n == 0)
    noteholder.parentNode.removeChild(noteholder);
  else {
    // Process footnoterefs.
    for (i=0; i<spans.length; i++) {
      if (spans[i].className == "footnoteref") {
        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
        href = href.match(/#.*/)[0];  // Because IE return full URL.
        n = refs[href];
        spans[i].innerHTML =
          "[<a href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
      }
    }
  }
},

install: function(toclevels) {
  var timerId;

  function reinstall() {
    asciidoc.footnotes();
    if (toclevels) {
      asciidoc.toc(toclevels);
    }
  }

  function reinstallAndRemoveTimer() {
    clearInterval(timerId);
    reinstall();
  }

  timerId = setInterval(reinstall, 500);
  if (document.addEventListener)
    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
  else
    window.onload = reinstallAndRemoveTimer;
}

}
asciidoc.install(2);
/*]]>*/
</script>
</head>
<body class="article">
<div id="header">
<h1>Release notes for Gerrit 2.0.21</h1>
<span id="revnumber">version 2.0.21 (from v2.7-rc2-530-g4d7ac77)</span>
<div id="toc">
  <div id="toctitle">Table of Contents</div>
  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>Gerrit 2.0.21 is now available in the usual location:</p></div>
<div class="paragraph"><p><a href="http://code.google.com/p/gerrit/downloads/list">http://code.google.com/p/gerrit/downloads/list</a></p></div>
</div>
</div>
<div class="sect1">
<h2 id="_schema_change">Schema Change</h2>
<div class="sectionbody">
<div class="paragraph"><p><strong>WARNING: This version contains a schema change</strong> (since 2.0.19)</p></div>
<div class="ulist"><ul>
<li>
<p>
The schema change may be difficult to undo once applied.
</p>
<div class="paragraph"><p>Downgrading could be very difficult once the upgrade has been
started.  Going back to 2.0.20 may not be possible.</p></div>
</li>
<li>
<p>
Do not run the schema change while the server is running.
</p>
<div class="paragraph"><p>This upgrade changes the primary key of a table, an operation
which shouldn&#8217;t occur while end-users are able to make
modifications to the database.  I <em>strongly</em> suggest a full
shutdown, schema upgrade, then startup approach for this release.</p></div>
</li>
<li>
<p>
There may be some duplicate keys
</p>
<div class="paragraph"><p>This upgrade removes a column from the primary key of a table,
which may result in duplicates being found.  You can search
for these duplicates before updating:
{{{
SELECT account_id,external_id FROM account_external_ids e
WHERE e.external_id IN (SELECT external_id
FROM account_external_ids
GROUP BY external_id
HAVING COUNT(*) &gt; 1);
}}}
Resolving duplicates is left up to the administrator, in
general though you will probably want to remove one of the
duplicate records.  E.g. in one case I had 3 users with the
same mailing list email address registered.  I just deleted
those and sent private email asking the users to use their
personal/work address instead of a mailing list.
Apply the database specific schema script:</p></div>
</li>
</ul></div>
<div class="listingblock">
<div class="content">
<pre><tt>  java -jar gerrit.war --cat sql/upgrade017_018_postgres.sql | psql reviewdb
  java -jar gerrit.war --cat sql/upgrade017_018_mysql.sql    | mysql reviewdb</tt></pre>
</div></div>
</div>
</div>
<div class="sect1">
<h2 id="_important_notices">Important Notices</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
Prior User Sessions
</p>
<div class="paragraph"><p>The cookie used to identify a signed-in user has been changed.
Again.  All users will be automatically signed-out during
this upgrade, and will need to sign-in again after the upgrade
is complete.  The new schema has more room for extensions, so
this might be the last time we will need to invalidate sessions.</p></div>
</li>
<li>
<p>
Harmless error on first startup
</p>
<div class="paragraph"><p>Starting 2.0.21 on an instance which previously had the diff
cache stored on disk will result in the following non-fatal error
in the server logs during the first launch of .21 on that system:</p></div>
</li>
</ul></div>
<div class="listingblock">
<div class="content">
<pre><tt>2009-09-02 18:50:07,446::INFO : com.google.gerrit.server.cache.CachePool  - Enabling disk cache /home/gerrit2/android_codereview/disk_cache
Sep 2, 2009 6:50:07 PM net.sf.ehcache.store.DiskStore readIndex
SEVERE: Class loading problem reading index. Creating new index. Initial cause was com.google.gerrit.server.patch.DiffCacheKey
java.lang.ClassNotFoundException: com.google.gerrit.server.patch.DiffCacheKey
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
...</tt></pre>
</div></div>
<div class="literalblock">
<div class="content">
<pre><tt>This error can be safely ignored.  It is caused by a change
in the diff cache's on disk schema, invalidating all existing
cache entries.</tt></pre>
</div></div>
<div class="ulist"><ul>
<li>
<p>
Significantly larger "diff" cache
</p>
<div class="paragraph"><p>The diff cache schema change noted above changed the element
stored in the cache from per-file to per-patchset.  That is,
a patch set which modifies 500 files will now occupy only 1
element in the diff cache, rather than 500 distinct elements.
Accordingly, the default <tt>cache.diff.memoryLimit</tt> setting has
been reduced to 128.</p></div>
</li>
<li>
<p>
Removed configuration settings
</p>
<div class="paragraph"><p>The following configuration settings are no longer honored:
<tt>cache.maxAge</tt>, <tt>cache.memoryLimit</tt>, <tt>cache.diskLimit</tt>, and
<tt>cache.diskBuffer</tt>.  These settings may now only be set on a
per-cache basis (e.g. <tt>cache.diff.maxAge</tt>).</p></div>
</li>
<li>
<p>
Connection pool recommendation: Apache Commons DBCP
</p>
<div class="paragraph"><p>All of the servers I run now use Apache Commons DBCP instead
of c3p0 for their connection pools, and the setup guide and
sample jetty_gerrit.xml reference DBCP now.
We&#8217;ve run into problems with c3p0 under high loads, or when
the connection pool is completely exhausted.  DBCP seems to
fail more gracefully, and seems to give us less trouble.
Changing pool implementations is not required, c3p0 is still
a supported provider.  I just want to make it clear that I no
longer recommend it in production.</p></div>
</li>
</ul></div>
</div>
</div>
<div class="sect1">
<h2 id="_new_features">New Features</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
GERRIT-189  Show approval status in account dashboards
</p>
<div class="paragraph"><p>Account dashboards now show a summary of the approval status on
each change.  Unreviewed changes are now highlighted to bring
the reviewer&#8217;s attention to them.  Tooltips when hovering over
a cell will bring up slightly more detailed information.</p></div>
</li>
<li>
<p>
GERRIT-276  Allow users to see what groups they are members of
</p>
<div class="paragraph"><p>Under Settings &gt; Groups a user can now view what groups Gerrit
has placed them into.  This may help administrators to debug
a user&#8217;s access problems, as they can ask the user to verify
Gerrit is seeing what they expect.</p></div>
</li>
<li>
<p>
GERRIT-276  Show simple properties of an LDAP group
</p>
<div class="paragraph"><p>If auth.type is HTTP_LDAP, groups which are marked as automatic
membership now show non-repeating LDAP attributes below their
description under Admin &gt; Groups.  This display should help an
administrator to verify that Gerrit has mapped an LDAP group
correctly.</p></div>
</li>
<li>
<p>
Move Patch entity out of database and store in cache
</p>
<div class="paragraph"><p>The <tt>patches</tt> database table has been deleted, Gerrit now makes
the list of affected files on the fly and stores it within the
diff cache.  This change is part of a long-running series to
remove redundant information from the database before we switch
to a pure Git backed data storage system.</p></div>
</li>
<li>
<p>
Only copy blocking negative votes to replacement patch
</p>
<div class="paragraph"><p>Previously Gerrit copied any negative vote in any approval
category whenever a replacement patch set was uploaded to
a change.  Now Gerrit only copies "Code Review -2".
This change should make it easier for reviewers (and scripts
scanning <tt>patch_set_approvals</tt>) to identify updated changes
which might require a new review.
Adminstrators who have created their own categories and want to
copy the blocking negative vote should set <tt>copy_min_score = 'Y'</tt>
in the corresponding approval_categories records.</p></div>
</li>
<li>
<p>
show-caches: Make output more concise
</p>
<div class="paragraph"><p>Instead of showing ~12 lines of output per cache, each cache is
displayed as one line of a table.</p></div>
</li>
<li>
<p>
Handle multiple accountBase and groupBase
</p>
<div class="paragraph"><p>ldap.accountBase and ldap.groupBase may now be specified multiple
times in gerrit.config, to search more than one subtree within
the directory.</p></div>
</li>
<li>
<p>
Summarize collapsed comments
</p>
<div class="paragraph"><p>Collapsed comments (both inline on a file and on the change
itself) now show a short summary of the comment message, making
it faster to locate the relevant comment to expand for more
detailed reading.</p></div>
</li>
<li>
<p>
Edit inline drafts on Publish Comments screen
</p>
<div class="paragraph"><p>Inline comment drafts may now be directly edited on the Publish
Comments screen, which can be useful for fixing up a minor typo
prior to publication.</p></div>
</li>
<li>
<p>
Less toggly thingies on change screen
</p>
<div class="paragraph"><p>The change description and the approvals are no longer nested
inside of a foldy block.  Most users never collapse these, but
instead just scroll the page to locate the information they are
looking for.</p></div>
</li>
<li>
<p>
Restore Enter/o to toggle collapse state of comments
</p>
<div class="paragraph"><p>Enter and <em>o</em> now expand or collapse an inline comment on the
the current row of a file.</p></div>
</li>
<li>
<p>
Display abbreviated hexy Change-Id in screen titles
</p>
</li>
<li>
<p>
Use hexy Change-Id in emails sent from Gerrit
</p>
<div class="paragraph"><p>Change-Id abbreviations are now used through more of the UI,
including emails sent by Gerrit and window/page titles.  This
change breaks email threading for any existing review emails.
That is comments on a change created before the upgrade will
not appear under the original change notification thread.</p></div>
</li>
<li>
<p>
Add sendemail.from to control setting From header
</p>
<div class="paragraph"><p>Gerrit no longer forges the From header in notification emails.
To enable the prior forging behavior, set <tt>sendemail.from</tt>
to <tt>USER</tt> in gerrit.config.  For more details see
<a href="http://gerrit.googlecode.com/svn/documentation/2.0/config-gerrit.html#sendemail.from">sendemail.from</a></p></div>
</li>
</ul></div>
</div>
</div>
<div class="sect1">
<h2 id="_bug_fixes">Bug Fixes</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
Fix ReviewDb to actually be per-request scoped
</p>
<div class="paragraph"><p>When we switched to Guice a misconfiguration allowed Guice to
give out multiple database connections per web or SSH request.
This could exhaust the connection pool faster than expected.</p></div>
</li>
<li>
<p>
Send no-cache headers during HTTP login
</p>
<div class="paragraph"><p>An oversight in the HTTP login code path may have allowed a proxy
server between the user&#8217;s browser and the Gerrit server to cache
a user&#8217;s session cookie.  Fixed by sending the correct no-cache
headers, disallowing any caching of the authentication response.</p></div>
</li>
<li>
<p>
Fix project owner permissions
</p>
<div class="paragraph"><p>Folks reported on repo-discuss that a project owner also had to
have READ permission to use the Branches tab of their project.
This was a regression introduced when we refactored some of the
code when adding Guice to the project.  Fixed.</p></div>
</li>
<li>
<p>
GERRIT-277  Fix hyperlinks in messages
</p>
<div class="paragraph"><p>Hyperlinks in commit messages such as "<a href="http://foo">http://foo</a>" were
including the trailing &gt; in the URL, making the link broken.
The trailing &gt; is now properly not included in the URL.</p></div>
</li>
<li>
<p>
GERRIT-266  Fix web session cookie refresh time
</p>
<div class="paragraph"><p>In 2.0.19 we introduced web sessions stored in Ehcache, but the
logic was causing sessions to expire roughly half-way through the
<tt>cache.web_sessions.maxAge</tt> time.  At the default setting, active
sessions were expiring after 6 hours.  The cache management has
been refactored to make this a lot less likely.</p></div>
</li>
<li>
<p>
Cleanup not signed in error to be more user friendly
</p>
<div class="paragraph"><p>The error message which comes up when your session is expired
is now much more useful.  From the dialog you can restart your
session by clicking the "Sign-In" button, and return to the
screen you are currently on.</p></div>
</li>
<li>
<p>
Fix commit-msg hook to work with commit -v option
</p>
<div class="paragraph"><p>The commit-msg hook was buggy and did not handle <tt>git commit -v</tt>
correctly.  It also did some bad insertions, placing the magic
<tt>Change-Id: I...</tt> line at the wrong position in the commit
message.  The updated hook resolves most of these problems,
but must be recopied to individual Git repositories by end-users.</p></div>
</li>
<li>
<p>
Identify PGP configuration errors during startup
</p>
<div class="paragraph"><p>If the encrypted contact store is enabled, the required encryption
algorithms are checked at startup to ensure they are enabled
in the underlying JVM.  This is necessary in case the JVM is
updated and the administrator forgot to install the unlimited
strength policy file in the new runtime directory.  Recently
review.source.android.com was bitten by just such an upgrade.</p></div>
</li>
<li>
<p>
GERRIT-278  Fix missing reply comments on old patch set
</p>
<div class="paragraph"><p>Some comments were not visible because they were replies made
to a comment on say patch set 1 while looking at the difference
between patch set 1 and patch set 2 of a change.  Fixed.</p></div>
</li>
<li>
<p>
Make external_id primary key of account_external_ids
</p>
<div class="paragraph"><p>The database schema incorrectly allowed two user accounts to have
the same email address, or to have the same OpenID auth token.
Fixed by asserting a unique constraint on the column.</p></div>
</li>
</ul></div>
</div>
</div>
<div class="sect1">
<h2 id="_other_changes">Other Changes</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
Start 2.0.21 development
</p>
</li>
<li>
<p>
Support cleaning up a Commons DBCP connection pool
</p>
</li>
<li>
<p>
Clarify which Factory we are importing in ApproveComma&#8230;
</p>
</li>
<li>
<p>
Avoid loading Patch object in /cat/ servlet
</p>
</li>
<li>
<p>
Remove unnecessary reference of patch key in save draft
</p>
</li>
<li>
<p>
GERRIT-266  Tweak cache defaults to be more reasonable
</p>
</li>
<li>
<p>
Merge change I131e6c4c
</p>
</li>
<li>
<p>
Bring back the "No Differences" message when files are&#8230;
</p>
</li>
<li>
<p>
Pick up gwtorm 1.1.2-SNAPSHOT
</p>
</li>
<li>
<p>
Refactor GroupListScreen&#8217;s inner table for reuse
</p>
</li>
<li>
<p>
Do not normalize approval scores on closed changes in &#8230;
</p>
</li>
<li>
<p>
Don&#8217;t obtain 0 approvals or submit approvals in dashbo&#8230;
</p>
</li>
<li>
<p>
Update JGit to 0.5.0-93-g5b89a2c
</p>
</li>
<li>
<p>
Add tests for Change-Id generating commit-msg hook
</p>
</li>
<li>
<p>
Add test for commit-msg with commit -v
</p>
</li>
<li>
<p>
Fix formatting error in ApprovalCategory
</p>
</li>
<li>
<p>
Fix typo in change table column header "Last Update"
</p>
</li>
<li>
<p>
Fix reference to the All Projects broken when we remov&#8230;
</p>
</li>
<li>
<p>
Use category abbreviations in the dashboard approval c&#8230;
</p>
</li>
<li>
<p>
Format approvals columns in change tables with minimal&#8230;
</p>
</li>
<li>
<p>
Shrink the Last Updated column in dashboards and chang&#8230;
</p>
</li>
<li>
<p>
Highlight changes which need to be reviewed by this us&#8230;
</p>
</li>
<li>
<p>
Fix typo in ChangeTable comment
</p>
</li>
<li>
<p>
Reduce the window used for "Mon dd" vs. "Mon dd yyyy" &#8230;
</p>
</li>
<li>
<p>
Don&#8217;t assume "Anonymous Users" and "Registered Users" &#8230;
</p>
</li>
<li>
<p>
Log encrypted contact store failures
</p>
</li>
<li>
<p>
Identify PGP configuration errors during startup
</p>
</li>
<li>
<p>
Take the change description block out of the disclosure&#8230;
</p>
</li>
<li>
<p>
Move the approval table out of a disclosure panel
</p>
</li>
<li>
<p>
Explicitly show what value is needed to submit
</p>
</li>
<li>
<p>
Modernize the display of comments on a change
</p>
</li>
<li>
<p>
Modernize the display of inline comments on a file
</p>
</li>
<li>
<p>
Fix "Publish Comments" when there are no inline drafts
</p>
</li>
<li>
<p>
Merge change 11666
</p>
</li>
<li>
<p>
Fix display of "Gerrit Code Review" authored comments
</p>
</li>
<li>
<p>
Fix source code formatting error in FormatUtil
</p>
</li>
<li>
<p>
Remove unnecessary fake author on inline comments
</p>
</li>
<li>
<p>
Auto expand all drafts on publish comments screen
</p>
</li>
<li>
<p>
Remove unused local variable in PublishCommentsScreen
</p>
</li>
<li>
<p>
Remove unused import from PublishCommentsScreen
</p>
</li>
<li>
<p>
Use gwtorm, gwtexpui release versions
</p>
</li>
<li>
<p>
Add javadoc for Change.getKey
</p>
</li>
<li>
<p>
Updated documentation for eclipse development.
</p>
</li>
<li>
<p>
Merge change 11698
</p>
</li>
<li>
<p>
Merge change 11699
</p>
</li>
<li>
<p>
Merge change 11700
</p>
</li>
<li>
<p>
Merge change 11703
</p>
</li>
<li>
<p>
Merge change 11705
</p>
</li>
<li>
<p>
Moved creation of GerritPersonIdent to a separate provi&#8230;
</p>
</li>
<li>
<p>
Remove unused dependency on GerritServer.
</p>
</li>
<li>
<p>
Renamed GerritServert to GitRepositoryManager and moved&#8230;
</p>
</li>
<li>
<p>
Remove declaration of OrmException that is never thrown.
</p>
</li>
<li>
<p>
Increase margin space between buttons of comment editors
</p>
</li>
<li>
<p>
Simplify GerritCallback error handling
</p>
</li>
<li>
<p>
Correct comment documenting SignInDialog
</p>
</li>
<li>
<p>
Remove unused CSS class gerrit-ErrorDialog-ErrorMessage
</p>
</li>
<li>
<p>
Clarify become any account servlet errors
</p>
</li>
<li>
<p>
Fix anchor in sshd.reuseAddress documentation
</p>
</li>
<li>
<p>
Extract parametrized string formatting out of LdapQuery
</p>
</li>
<li>
<p>
Make cache APIs interfaces for mocking
</p>
</li>
<li>
<p>
Add easymock 2.5.1 to our test dependencies
</p>
</li>
<li>
<p>
Add sendemail.from to control setting From header
</p>
</li>
<li>
<p>
gerrit 2.0.21
</p>
</li>
</ul></div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Version 2.0.21 (from v2.7-rc2-530-g4d7ac77)<br />
Last updated 2013-10-08 10:02:12 PDT
</div>
</div>
</body>
</html>
